import urllib.request
import io

def download_data(url):
    """下载数据文件"""
    print(f"正在下载数据: {url}")
    response = urllib.request.urlopen(url)
    data = response.read().decode('utf-8')
    print("数据下载完成")
    return data

def load_iris_data():
    """加载Iris数据集"""
    url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
    data = download_data(url)
    
    lines = data.strip().split('\n')
    X = []
    y = []
    class_names = []
    class_map = {}
    
    for line in lines:
        if line.strip():  # 跳过空行
            parts = line.split(',')
            if len(parts) == 5:  # 4个特征 + 1个标签
                # 提取特征
                features = [float(x) for x in parts[:4]]
                X.append(features)
                
                # 处理标签
                label = parts[4].strip()
                if label not in class_map:
                    class_map[label] = len(class_names)
                    class_names.append(label)
                y.append(class_map[label])
    
    return X, y, class_names

def load_wine_data():
    """加载Wine数据集"""
    url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data'
    data = download_data(url)
    
    lines = data.strip().split('\n')
    X = []
    y = []
    
    for line in lines:
        if line.strip():  # 跳过空行
            parts = line.split(',')
            if len(parts) == 14:  # 1个类别 + 13个特征
                # 第一列是类别
                class_label = int(parts[0])
                y.append(class_label)
                
                # 剩余13列是特征
                features = [float(x) for x in parts[1:]]
                X.append(features)
    
    return X, y

def train_test_split(X, y, test_size=0.3, random_state=None):
    """手动实现训练测试集分割"""
    if random_state is not None:
        import random
        random.seed(random_state)
    
    n_samples = len(X)
    n_test = int(n_samples * test_size)
    
    # 创建索引并打乱
    indices = list(range(n_samples))
    if random_state is not None:
        random.shuffle(indices)
    else:
        import random
        random.shuffle(indices)
    
    test_indices = indices[:n_test]
    train_indices = indices[n_test:]
    
    X_train = [X[i] for i in train_indices]
    X_test = [X[i] for i in test_indices]
    y_train = [y[i] for i in train_indices]
    y_test = [y[i] for i in test_indices]
    
    return X_train, X_test, y_train, y_test

def standardize(X):
    """数据标准化"""
    if not X:
        return X
    
    n_features = len(X[0])
    n_samples = len(X)
    
    # 计算均值和标准差
    means = [0] * n_features
    stds = [0] * n_features
    
    # 计算均值
    for sample in X:
        for i in range(n_features):
            means[i] += sample[i]
    means = [m / n_samples for m in means]
    
    # 计算标准差
    for sample in X:
        for i in range(n_features):
            stds[i] += (sample[i] - means[i]) ** 2
    stds = [(s / n_samples) ** 0.5 for s in stds]
    
    # 标准化数据（避免除零）
    X_std = []
    for sample in X:
        new_sample = []
        for i in range(n_features):
            if stds[i] != 0:
                new_sample.append((sample[i] - means[i]) / stds[i])
            else:
                new_sample.append(0.0)
        X_std.append(new_sample)
    
    return X_std

def discretize_data(X, n_bins=3):
    """离散化连续数据"""
    if not X:
        return X
    
    n_features = len(X[0])
    n_samples = len(X)
    X_disc = []
    
    for feature_idx in range(n_features):
        # 提取该特征的所有值
        feature_values = [sample[feature_idx] for sample in X]
        min_val = min(feature_values)
        max_val = max(feature_values)
        
        # 计算分箱边界
        bin_width = (max_val - min_val) / n_bins
        bins = [min_val + i * bin_width for i in range(n_bins + 1)]
        
        # 离散化该特征
        for i, sample in enumerate(X):
            if i >= len(X_disc):
                X_disc.append([0] * n_features)
            
            value = sample[feature_idx]
            bin_idx = 0
            for j in range(n_bins):
                if bins[j] <= value < bins[j+1]:
                    bin_idx = j
                    break
                elif j == n_bins - 1 and value >= bins[j+1]:
                    bin_idx = j
            X_disc[i][feature_idx] = bin_idx
    
    return X_disc